<template>
  <el-input
    ref="baseInputRef"
    v-bind="props"
    v-model.trim="baseData.search"
    class="base-input-search"
    style="width: 100%"
    clearable
    @blur="blurEvent"
    @input="inputEvent"
    @keydown.enter.stop.prevent="$throttle(handleEnterEvent, $event)"
    @clear="$throttle(handleSearchSubmit)"
  >
    <template v-if="$slots.prefix" #prefix>
      <slot name="prefix"></slot>
    </template>
    <template v-if="$slots.suffix" #suffix>
      <slot name="suffix"></slot>
    </template>
    <template v-if="$slots.prepend" #prepend>
      <slot name="prepend"></slot>
    </template>
    <template #append>
      <slot name="append">
        <el-button
          class="search-butt"
          :size="globalSize"
          :disabled="disabled"
          :loading="loading"
          v-bind="{ tabindex }"
          :icon="IconSolarMagniferLinear"
          style="max-width: 62px"
          @click="$throttle(handleButtonEvent, $event)"
        ></el-button>
      </slot>
    </template>
  </el-input>
</template>

<script setup lang="ts">
  import { inputProps } from 'element-plus';
  import IconSolarMagniferLinear from '~icons/solar/magnifer-linear';

  const props = defineProps({
    ...inputProps,
    /** 输入框尺寸，只在 type 不为 'textarea' 时有效 */
    size: { type: String as PropType<$GlobalSize>, default: undefined },
    /** 加载状态 (是否正在搜索中) */
    loading: { type: Boolean, default: false },
    /** 搜索值为空时是否禁止搜索 */
    forbidEmptySearch: { type: Boolean, default: false },
    /** 绑定值 */
    modelValue: { type: String, default: '' },
    /** 是否禁用 */
    disabled: { type: Boolean, default: false },
    /** 输入框的 tabindex */
    tabindex: { type: Number, default: undefined },
  });
  defineSlots<{
    /** 输入框头部内容 (输入框里面)，只对非 type="textarea" 有效 */
    prefix: () => void;
    /** 输入框尾部内容 (输入框里面)，只对非 type="textarea" 有效 */
    suffix?: () => void;
    /** 输入框前置内容 (输入框外面)，只对非 type="textarea" 有效 */
    prepend?: () => void;
    /** 输入框后置内容 (输入框外面)，只对非 type="textarea" 有效 */
    append?: () => void;
  }>();
  const emit = defineEmits<{
    (e: 'update:modelValue', val: number | string): void;
    (e: 'submit', search: number | string, event: HTMLElement): void;
    (e: 'enter', search: number | string, event: HTMLElement): void;
    (e: 'input', value: number | string, original: number | string): void;
    (e: 'blur', event: FocusEvent): void;
  }>();

  const globalSize = computed(() => props.size || useGlobalStore().globalSize);

  const baseData = shallowReactive({
    search: props.modelValue,
  });
  watchEffect(() => {
    baseData.search = props.modelValue;
  });
  watchEffect(() => {
    emit('update:modelValue', baseData.search);
  });

  /**
   * 点击搜索按钮
   */
  function handleButtonEvent(event: MouseEvent) {
    const dom = (event.currentTarget as HTMLElement).parentNode?.parentNode;
    dom && handleSearchSubmit(dom as HTMLElement);
  }

  /**
   * 点击回车键
   */
  function handleEnterEvent(event: KeyboardEvent) {
    const dom = (event.currentTarget as HTMLElement).parentNode;
    if (dom) {
      emit('enter', baseData.search, dom as HTMLElement);
      handleSearchSubmit(dom as HTMLElement);
    }
  }

  /**
   * elDom 代表el-input的元素 主要用于弹出框等(不用可忽略)
   */
  function handleSearchSubmit(elDom: HTMLElement) {
    if (!props.forbidEmptySearch || baseData.search) {
      nextTick(() => {
        emit('submit', baseData.search, elDom);
      });
    }
  }

  /**
   * 输入改变时触发
   */
  function inputEvent(value: number | string) {
    nextTick(() => {
      emit('input', baseData.search, value);
    });
  }

  /**
   * 失去焦点时触发
   */
  function blurEvent(event: FocusEvent) {
    emit('blur', event);
  }

  const baseInputRef: $RefComp<'ElInput'> = ref(null);

  defineExpose({
    /** 搜索框聚焦 */
    focus: () => {
      baseInputRef.value && baseInputRef.value?.focus && baseInputRef.value.focus();
    },
  });
</script>
